package com.hnx.admin.aurora.utils;

import com.hnx.admin.aurora.web.json.FieldInfo;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

/*
创建人： 倔强的头发
创建时间：2025/6/18
功能描述: 通用注解字段反射工具类
         支持任意注解标记的字段信息

*/
@Slf4j
public class AnnReflectionUtil {
    //缓存结构： 类->（注解类型->字段列表）
    private static final Map<Class<?>, Map<Class<? extends Annotation>, List<Field>>> ANNOTATION_FIELD_CACHE = new ConcurrentHashMap<>(64);
    private static final Map<Field, Function<Object, Object>> FIELD_VALUE_GETTER_CACHE = new ConcurrentHashMap<>(256);

    private AnnReflectionUtil() {
        throw new UnsupportedOperationException("工具类不允许实例化");
    }

    /*
     * 获取类中所在被指定注解标记的字段
     * */
    public static List<Field> getAnnotationFields(Class<?> clazz, Class<? extends Annotation> annotationClass) {
        return getCachedFields(clazz, annotationClass);
    }

    /*
     * 获取缓存字段(带双重检查锁)
     * */
    private static List<Field> getCachedFields(Class<?> clazz, Class<? extends Annotation> annotationClass) {
        //第一级缓存：类级另的注解字段映射
        Map<Class<? extends Annotation>, List<Field>> map = ANNOTATION_FIELD_CACHE.computeIfAbsent(clazz, k -> new ConcurrentHashMap<>(8));
        return map.computeIfAbsent(annotationClass, k -> {
            List<Field> fields = resolveAnnotatedFields(clazz, annotationClass);
            return Collections.unmodifiableList(fields);
        });
    }

    private static List<Field> resolveAnnotatedFields(Class<?> clazz, Class<? extends Annotation> annotationClass) {
        Field[] fields = clazz.getDeclaredFields();
        return Arrays.stream(fields).filter(n -> n.isAnnotationPresent(annotationClass)).collect(Collectors.toList());
    }
    public static Object getFieldValue(Object obj,Field field){
        Function<Object,Object> valueGetter = FIELD_VALUE_GETTER_CACHE.computeIfAbsent(field,f->{
            return o->{
                try{
                    f.setAccessible(true);
                    return f.get(o);
                }
                catch (Exception ex){
                    log.error("反射获取属性值失败:"+ex.getMessage());
                    return null;
                }
            };
        });
        return valueGetter.apply(obj);
    }
    /*
    * 获取类中所有被指定注解标记的字段名称
    * */
    public static List<String> getAnnotatedFieldName(Class<?> clazz, Class<? extends Annotation> annotationClass){
        return getCachedFields(clazz,annotationClass).stream().map(Field::getName).collect(Collectors.toList());
    }
    public static Map<String,Object> getAnnotatedFieldValues(Object obj, Class<? extends Annotation> annotationClass){
        if(Objects.nonNull(obj)){
            List<Field> cachedFields = getCachedFields(obj.getClass(), annotationClass);
            Map<String,Object> map = new LinkedHashMap<>(cachedFields.size());
            for(Field field: cachedFields){
                try{
                    Object value = getFieldValue(obj,field);
                    map.put(field.getName(),value);
                }catch (Exception ex){
                    map.put(field.getName(),null);
                }
            }
            return Collections.unmodifiableMap(map);
        }
        return Collections.emptyMap();
    }
    public static List<FieldInfo> getFieldInfo(Object obj,Class<? extends Annotation> annotationClss){
        if(Objects.nonNull(obj)){
            return getCachedFields(obj.getClass(),annotationClss).stream().map(field -> {
                try{
                    Object value = getFieldValue(obj,field);
                    Annotation annotation = field.getAnnotation(annotationClss);
                    return new FieldInfo(field.getName(),value,annotation);
                }
                catch (Exception ex){
                    return new FieldInfo(field.getName(), null,field.getAnnotation(annotationClss));
                }
            }).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

}
